/*
 * 本类作用：mina框架:解码器，用于接收数据时拆包
 * 
 * 作者：袁小杰
 * 博客：http://blog.csdn.net/undoner
 * GIT：https://git.oschina.net/undoner
 * QQ：15137281
 * 
 */
package com.smforj.ssm.mina.codec;
 
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderAdapter;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;

/**
 * 解码器，用于接收数据时拆包
 * */
public class MsgTotalDecoder extends ProtocolDecoderAdapter {

	static Logger log = Logger.getRootLogger();
	
	/**
	 * KEY
	 */
	private final AttributeKey CONTEXT = new AttributeKey(getClass(), "CONTEXT");

	private final Charset charset;

	private final int packHeadLength = 180;
 
	static int count = 0;

	public MsgTotalDecoder() {
		this(Charset.defaultCharset());
	}

	public MsgTotalDecoder(Charset charset) {
		this.charset = charset;
	}
	

	public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
			throws Exception { 
		log.debug("MsgDecoder.decode()"+count++);  
		 Context ctx = getContext(session);  
		 // 先把当前buffer中的数据追加到Context的buffer当中  
		 ctx.append(in);  
		 // 把position指向0位置，把limit指向原来的position位置  
		 IoBuffer buf = ctx.getBuffer();  
		 buf.flip();   
		 
		 while (buf.remaining() >= packHeadLength) {  
			    buf.mark();  
			    // 设置总长度  
			    if (ctx.getMsgLength() <= 0) {  
			        // 读取消息头部分  
			        byte[] bLeng = new byte[packHeadLength];  
			        buf.get(bLeng);  
			        int length = -1;  
			        try {  
			            //消息体长度包含消息头
			        	byte[] bytes = new byte[4];
			        	System.arraycopy(bLeng, 116, bytes, 0, bytes.length);
			        	length = MsgUtils.bytesToInt(bytes);
			                //length = Integer.parseInt(new String(bLeng));  
			            } catch (NumberFormatException ex) {  
			                    ex.printStackTrace();  
			            }  
			            if (length > 0) {  
			            	ctx.setMsgLength(length);  
			              }  
			            }   
			            // 读取消息头部分  
			            int length = ctx.getMsgLength();  
			            // 检查读取的包头是否正常，不正常的话清空buffer  
			            if (length < 0) { // || length > maxPackLength2) {  
			            	buf.clear();  
				            out.write("ERROR!");  
				            break;  
			            // 读取正常的消息包，并写入输出流中，以便IoHandler进行处理  
			          } else if (length > packHeadLength && buf.remaining() >= length) {  
			            //完整的数据读取之后，就可以开始做你自己想做的操作了    
			        	  out.write(ctx.buf); 
			    } else {  
			        // 如果消息包不完整  
			        // 将指针重新移动消息头的起始位置  
			        buf.reset();  
			        break;  
			    }  
			     }  
		    if (buf.hasRemaining()) { // 如果有剩余的数据，则放入Session中  
		       // 将数据移到buffer的最前面  
             IoBuffer temp = IoBuffer.allocate(2048).setAutoExpand(  
                        true);  
		       temp.put(buf);  
		       temp.flip();  
		       buf.clear();  
		       buf.put(temp);  
		    } else { // 如果数据已经处理完毕，进行清空  
		    	buf.clear();  
			}   
	}

	public void dispose(IoSession session) throws Exception {
		log.debug("MsgDecoder.dispose()");
	}
	
    /** 
     *  
     * @param session 
     *            会话信息 
     * @return 返回session中的累积 
     */  
    private Context getContext(IoSession session) {  
        Context ctx = (Context) session.getAttribute(CONTEXT);  
        if (ctx == null) {  
            ctx = new Context();  
            session.setAttribute(CONTEXT, ctx);  
        }  
        return ctx;  
    }   
	
	private class Context {
		private final CharsetDecoder decoder;
		private IoBuffer buf;
		private int msgLength = 0;
		private int overflowPosition = 0;

		/**
		 * 
		 * 
		 */
		private Context() {
			decoder = charset.newDecoder();
			buf = IoBuffer.allocate(80).setAutoExpand(true);
		}

		/**
		 * 
		 * 
		 * @return CharsetDecoder
		 */
		@SuppressWarnings("unused")
		public CharsetDecoder getDecoder() {
			return decoder;
		}

		/**
		 * 
		 * 
		 * @return IoBuffer
		 */
		public IoBuffer getBuffer() {
			return buf;
		}

		/**
		 * 
		 * 
		 * @return overflowPosition
		 */
		@SuppressWarnings("unused")
		public int getOverflowPosition() {
			return overflowPosition;
		}

		/**
		 * 
		 *
		 * @return matchCount
		 */
		public int getMsgLength() {
			return msgLength;
		}

		/**
		 * 
		 * 
		 * @param matchCount
		 *            报文长度
		 */
		public void setMsgLength(int msgLength) {
			this.msgLength = msgLength;
		}

		/**
		 * 
		 * 
		 */
		@SuppressWarnings("unused")
		public void reset() {
			this.buf.clear();
			this.overflowPosition = 0;
			this.msgLength = 0;
			this.decoder.reset();
		}

		/**
		 * 
		 * @param in
		 *            输入流
		 */
		public void append(IoBuffer in) {
			getBuffer().put(in);

		} 
	}


}
